﻿//#include "Collision.h"
//
//
//Collision::Collision(void)
//{
//
//}
//
//Collision::~Collision(void)
//{
//
//}
//
////bool Collision::isCollided(CPolygon A, CPolygon B, Vector &MTD)
////{
////	int n_a = A.getLength();	//số vector của đa giác A
////	int n_b = B.getLength();	//số vector của đa giác B
////
////	Vector N,E,E1,E2;
////	Vector* PushVectorList;
////
////	PushVectorList = new Vector[n_a + n_b];
////
////	for (int i=0,j=n_a - 1;i<n_a;j=i,i++)
////	{
////		E1 = A.getVertice(i);
////		E2 = A.getVertice(j);
////		E = E1 - E2;
////		N = Vector(- E.getY(), E.getX());
////		if (this->axisSeperatePolygon(N,A,B,PushVectorList[i]))
////			return false;
////	}
////
////	for (int i=0,j=n_b - 1;i<n_b;j=i,i++)
////	{
////		E = B.getVertice(i) - B.getVertice(j);
////		N = Vector(- E.getY(), E.getX());
////		if (this->axisSeperatePolygon(N,A,B,PushVectorList[n_a + i]))
////			return false;
////	}
////
////	//tìm pushvector có độ lớn nhỏ nhất
////	MTD = findMTD(PushVectorList,n_a + n_b);
////
////	Vector D = A.getVertice(0) - B.getVertice(0);
////
////	if (D * MTD < 0)
////		MTD = -MTD;
////
////	return true;
////}
//
//bool Collision::isCollided(CPolygon A, CPolygon B, Vector &MTD, Vector Vel, Vector &PushVelVector, bool &willCollide)
//{
//	int n_a = A.getLength();	//số vector của đa giác A
//	int n_b = B.getLength();	//số vector của đa giác B
//
//	int tem;
//
//	willCollide = false;
//
//	Vector N,E,E1,E2;
//	Vector* PushVectorList;
//	Vector* PushVelVectorList;
//
//	PushVectorList = new Vector[n_a + n_b];
//	PushVelVectorList = new Vector[n_a + n_b];
//	int numPushVelVector = 0;
//
//	for (int i=0,j=n_a - 1;i<n_a;j=i,i++)
//	{
//		E1 = A.getVertice(i);
//		E2 = A.getVertice(j);
//		E = E1 - E2;
//		N = Vector(- E.getY(), E.getX());
//		tem = this->axisSeperatePolygon(N,A,B,PushVectorList[i],Vel,PushVelVectorList,numPushVelVector);
//		if (tem == -1)
//			return false;
//		else if (tem == 0)
//			willCollide = true;
//	}
//
//	for (int i=0,j=n_b - 1;i<n_b;j=i,i++)
//	{
//		E = B.getVertice(i) - B.getVertice(j);
//		N = Vector(- E.getY(), E.getX());
//		tem = this->axisSeperatePolygon(N,A,B,PushVectorList[n_a + i],Vel,PushVelVectorList,numPushVelVector);
//		if (tem == -1)
//			return false;
//		else if (tem == 0)
//			willCollide = true;
//		//if (tem != 1) return false;
//	}
//
//	Vector D = A.getVertice(0) - B.getVertice(0);
//	
//	//va chạm, tìm pushvector có độ lớn nhỏ nhất
//	if (!willCollide)
//	{
//		if (Vel.getX() >= 3.f || Vel.getY() >= 3.f)
//			MTD = findMTD1(PushVectorList,n_a + n_b,Vel);
//		else
//			MTD = findMTD2(PushVectorList,n_a + n_b);
//
//	//tìm pushvelvector có độ lớn lớn nhất
//		if (D * MTD < 0)
//			MTD = -MTD;
//	}
//	else
//	{
//		PushVelVector = findPushVelVector(PushVelVectorList,numPushVelVector);
//		if (PushVelVector * Vel < 0)
//			PushVelVector = -PushVelVector;
//		//MessageBox(NULL,L"Haha",L"Hoho",MB_OK);
//	}
//
//	delete[] PushVectorList;
//	delete[] PushVelVectorList;
//
//	return true;
//}
//
////bool Collision::isCollided(shared_ptr<MObject> OA, shared_ptr<MObject> OB)
////{
////	RECT arect = OA->getRect();
////	RECT brect = OB->getRect();
////	CPolygon A = OA->getPolygon();
////	CPolygon B = OB->getPolygon();
////
////	Vector Vel = OA->getVelocityVector();
////
////	Vector MTD,PushVelVector;
////	bool willCollide;
////	bool result = isCollided(A,B,MTD,OA->getVelocityVector(),PushVelVector,willCollide);
////
////	//xảy ra va chạm
////	if (result == true)
////	{
////		//sẽ va chạm trong khoảng từ vị trí hiện tại đến vị trí trong frame tiếp theo
////		if (willCollide)
////		{
////			if (PushVelVector * Vel > 0)
////				PushVelVector = -PushVelVector;
////			OA->setPushBackVector(PushVelVector);
////		}
////		else
////		{
////			OA->Translate((MTD));
////			//OA->Translate((float)1/2 * (MTD));
////			////OA->setVelocity(OA->getVelocityVector() + (float)1/2 * (MTD));
////			Vector vel = OA->getVelocityVector() + (float)1/2*OB->getVelocityVector();
////			Vector normalVector = (MTD.Normalise());
////			float f = (vel*normalVector);
////			Vector afterCollideVector = vel - ((1 + 1)*(f*normalVector));
////			OA->setVelocity(afterCollideVector);
////			//OB->Translate((float)1/2 * (-MTD));
////		}
////	}
////
////	return result;
////}
//
//bool Collision::isCollided(shared_ptr<MObject> OA, shared_ptr<MObject> OB)
//{
//
//	RECT arect = OA->getRect();
//	RECT brect = OB->getRect();
//
//	if (arect.top == brect.top && arect.left == brect.left && arect.bottom == brect.bottom && arect.right == brect.right)
//		return false;
//
//	CPolygon A = CPolygon(arect);
//	CPolygon B = CPolygon(brect);
//
//	Vector Vel = OA->getVelocityVector();
//
//	Vector MTD,PushVelVector;
//	bool willCollide;
//	bool result = isCollided(A,B,MTD,OA->getVelocityVector(),PushVelVector,willCollide);
//
//	//Vector v=Vector();
//
//	//xảy ra va chạm
//	if (result == true)
//	{
//		//sẽ va chạm trong khoảng từ vị trí hiện tại đến vị trí trong frame tiếp theo
//		if (willCollide)
//		{
//			if (PushVelVector * Vel > 0)
//				PushVelVector = -PushVelVector;
//			OA->setPushBackVector(PushVelVector);
//		}
//
//		else
//		{
//				//OA->Translate(MTD);
//			if (OB->isMovable())
//			{
//				OA->Translate((float)1/2 * (MTD),OB);
//				OB->Translate((float)1/2 * (-MTD),OA);
//			}
//			else 
//			{
//				OA->Translate(MTD,OB);
//				OB->Translate(Vector(),OA);
//			}
//			////OA->setVelocity(OA->getVelocityVector() + (float)1/2 * (MTD));
//
//
//			Vector vel = OA->getVelocityVector();// + (float)1/2*OB->getVelocityVector();
//			Vector normalVector = (MTD.Normalise());
//			float f = (vel*normalVector);
//			Vector afterCollideVector = vel - ((1.f)*(f*normalVector));
//			OA->setVelocity(afterCollideVector, OB);
//
//			//v = MTD;
//
//		}
//
//	}
//
//	return result;
//}
//
////bool Collision::isCollided(shared_ptr<MObject> OA, shared_ptr<MObject> OB)
////{
////
////	RECT arect = OA->getRect();
////	RECT brect = OB->getRect();
////
////	if (arect.top == brect.top && arect.left == brect.left && arect.bottom == brect.bottom && arect.right == brect.right)
////		return false;
////
////	CPolygon A = CPolygon(arect);
////	CPolygon B = CPolygon(brect);
////
////	Vector Vel = OA->getVelocityVector();
////
////	Vector MTD,PushVelVector;
////	bool willCollide;
////	bool result = isCollided(A,B,MTD,OA->getVelocityVector(),PushVelVector,willCollide);
////
////	//Vector v=Vector();
////
////	//xảy ra va chạm
////	if (result == true)
////	{
////		//sẽ va chạm trong khoảng từ vị trí hiện tại đến vị trí trong frame tiếp theo
////		if (willCollide)
////		{
////			if (PushVelVector * Vel > 0)
////				PushVelVector = -PushVelVector;
////			OA->setPushBackVector(PushVelVector);
////		}
////
////		else
////		{
////				//OA->Translate(MTD);
////			if (OB->isMovable())
////			{
////				OA->Translate((float)1/2 * (MTD),OB);
////				OB->Translate((float)1/2 * (-MTD),OA);
////			}
////			else 
////			{
////				OA->Translate(MTD,OB);
////				OB->Translate(Vector(),OA);
////			}
////			////OA->setVelocity(OA->getVelocityVector() + (float)1/2 * (MTD));
////
////
////			Vector vel = OA->getVelocityVector();// + (float)1/2*OB->getVelocityVector();
////			Vector normalVector = (MTD.Normalise());
////			float f = (vel*normalVector);
////			Vector afterCollideVector = vel - ((1.f)*(f*normalVector));
////			OA->setVelocity(afterCollideVector, OB);
////
////			//v = MTD;
////
////		}
////
////	}
////
////	return result;
////}
//
//void Collision::getInterval(CPolygon polygon, Vector Axis, float &min, float &max)
//{
//	float d = polygon.getVertice(0) * Axis; // tích vô hướng của 2 vector: Vector có đỉnh 0 và vector Axis
//	min = max = d;
//	int numVertices = polygon.getLength();
//	for (int i=1;i<numVertices;i++)
//	{
//		d = polygon.getVertice(i) * Axis;
//		if (d < min) min = d;
//		else if (d > max) max = d;
//	}
//}
//
//int Collision::axisSeperatePolygon(Vector Axis,CPolygon A, CPolygon B, Vector &PushVector,Vector Vel, Vector* PushVelVectorList, int &numPushVelVector)
//{
//	float min1,min2,max1,max2;
//	PushVector = Axis;
//
//	getInterval(A,Axis,min1,max1);
//	getInterval(B,Axis,min2,max2);
//
//	float d1 = max1 - min2;
//	float d2 = max2 - min1;
//
//	//không xảy ra va chạm
//	if (d2 < 0 || d1 < 0)
//	{
//		d2 = fabs(d2);
//		d1 = fabs(d1);
//		float s = (d1 < d2) ? d1:d2;
//		s = (float)s/sqrt(Axis.Length());
//		float v = fabs(Vel * Axis);
//		if (s >= v)
//			return -1;
//		else
//		{
//			numPushVelVector++;
//			float k = (v-s) / (Axis*Axis);
//			PushVelVectorList[numPushVelVector - 1] = k * Axis;
//			return 0; //willCollide
//		}
//	}
//
//	else
//	{
//		float depth = d1 < d2 ? d1:d2;
//
//		float squareAxisLength = Axis * Axis;
//
//		PushVector = Axis * (float)(depth/squareAxisLength);
//		return 1; //collided
//	}
//}
//
//Vector Collision::findMTD2(Vector* PushVectorList,int numItem)
//{
//	float minMagnitude = PushVectorList[0] * PushVectorList[0];
//	int i=0;
//	Vector vt;
//	float curMagnitude;
//	int index = 0;
//	for (int i=0;i<numItem;i++)
//	{
//		curMagnitude = PushVectorList[i] * PushVectorList[i];
//		if (curMagnitude < minMagnitude)
//		{
//			minMagnitude = curMagnitude;
//			index = i;
//		}
//	}
//
//	return PushVectorList[index];
//}
//
//Vector Collision::findMTD1(Vector* PushVectorList,int numItem, Vector ObjVector)
//{
//	int index = 0;
//	for (int i=0;i<numItem;i++)
//	{
//		if (PushVectorList[i] * ObjVector != 0)
//			index = i;
//	}
//
//	return PushVectorList[index];
//}
//
//
//Vector Collision::findPushVelVector(Vector *PushVelVectorList, int numItem)
//{
//	float maxMagnitude = PushVelVectorList[0] * PushVelVectorList[0];
//	float curMagnitude;
//	int index = 0;
//	for (int i=1;i<numItem;i++)
//	{
//		curMagnitude = PushVelVectorList[i] * PushVelVectorList[i];
//		if (curMagnitude > maxMagnitude)
//		{
//			maxMagnitude = curMagnitude;
//			index = i;
//		}
//	}
//	
//	return PushVelVectorList[index];
//	//return Vector();
//
//}

#include "Collision.h"

bool Collision::inside(const RECT &rect1,const RECT &rect2)
{
	if ((rect1.top >= rect2.top) && (rect1.left >= rect2.left) && (rect1.right <= rect2.right) && (rect1.bottom <= rect2.bottom))
		return true;
	else return false;
}


Collision::Collision(void)
{
	_deltaTime = 0;
}

Collision::~Collision(void)
{

}


bool Collision::isCollided(CPolygon A, CPolygon B, Vector &MTD, Vector Vel, float &minFloat, bool &willCollide)
{
	int n_a = A.getLength();	//số vector của đa giác A
	int n_b = B.getLength();	//số vector của đa giác B

	int tem;

	willCollide = false;

	Vector N,E,E1,E2;
	Vector* PushVectorList;
	float* floatList;

	PushVectorList = new Vector[n_a + n_b];
	floatList = new float[n_a + n_b];
	
	
	int numPushVelVector = 0;


	for (int i=0,j=n_a - 1;i<n_a;j=i,i++)
	{
		E1 = A.getVertice(i);
		E2 = A.getVertice(j);
		E = E1 - E2;
		N = Vector(- E.getY(), E.getX());
		tem = this->axisSeperatePolygon(N,A,B,PushVectorList[i],Vel,floatList,numPushVelVector);
		if (tem == -1)
			return false;
		else if (tem == 0)
			willCollide = true;
		//if (tem != 1) return false;
	}

	for (int i=0,j=n_b - 1;i<n_b;j=i,i++)
	{
		E = B.getVertice(i) - B.getVertice(j);
		N = Vector(- E.getY(), E.getX());
		tem = this->axisSeperatePolygon(N,A,B,PushVectorList[n_a + i],Vel,floatList,numPushVelVector);
		if (tem == -1)
			return false;
		else if (tem == 0)
			willCollide = true;
		//if (tem != 1) return false;
	}

	Vector D = A.getVertice(0) - B.getVertice(0);
	
	//va chạm, tìm pushvector có độ lớn nhỏ nhất
	if (!willCollide)
	{
		MTD = findMTD(PushVectorList,n_a + n_b);
		if (D * MTD < 0)
			MTD = -MTD;

	}
	else
	{
		/*PushVelVector = findPushVelVector(PushVelVectorList,numPushVelVector);
		if (PushVelVector * Vel < 0)
			PushVelVector = -PushVelVector;*/
		//MessageBox(NULL,L"Haha",L"Hoho",MB_OK);
		minFloat = findmin(floatList,numPushVelVector);
	}

	
	delete[] PushVectorList;
	delete[] floatList;
	return true;
}

bool Collision::isCollided(shared_ptr<MObject> OA, shared_ptr<MObject> OB)
{
	RECT arect = OA->getRect();
	RECT brect = OB->getRect();
	CPolygon A = CPolygon(arect);
	CPolygon B = CPolygon(brect);

	
	Vector MTD;
	float minFloat;
	bool willCollide;
	bool result;
	if (inside(arect,brect))
	{
		Vector D = A.getVertice(0) - B.getVertice(0);
		MTD = OA->getVelocityVector() * _deltaTime;
		if (D * MTD > 0)
			MTD = -MTD;
      	OA->setVelocity(Vector(),OB);
		result = true;
		willCollide = false;
	}
	else
		result = isCollided(A,B,MTD,OA->getVelocityVector(),minFloat,willCollide);

	//xảy ra va chạm
	if (result == true)
	{
		//sẽ va chạm trong khoảng từ vị trí hiện tại đến vị trí trong frame tiếp theo
		if (willCollide)
		{
			/*if (PushVelVector * Vel > 0)
				PushVelVector = -PushVelVector;
			OA->setPushBackVector(PushVelVector);*/
			OA->setPercent(minFloat);
		}
		else
		{
			
			//OA->Translate(MTD);
			if (OB->isMovable())
			{
				OA->Translate((float)1/2 * (MTD),OB);
				OB->Translate((float)1/2 * (-MTD),OA);
			}
			else 
			{
				OA->Translate(MTD,OB);
				OB->Translate(Vector(),OA);
			}
			////OA->setVelocity(OA->getVelocityVector() + (float)1/2 * (MTD));
			
			
			Vector vel = OA->getVelocityVector();// + (float)1/2*OB->getVelocityVector();
			Vector normalVector = (MTD.Normalise());
			float f = (vel*normalVector);
			Vector afterCollideVector = vel - ((1.f)*(f*normalVector));
			OA->setVelocity(afterCollideVector, OB);
		}
	}

	return result;
}

void Collision::getInterval(CPolygon polygon, Vector Axis, float &min, float &max)
{
	float d = polygon.getVertice(0) * Axis; // tích vô hướng của 2 vector: Vector có đỉnh 0 và vector Axis
	min = max = d;
	int numVertices = polygon.getLength();
	for (int i=1;i<numVertices;i++)
	{
		d = polygon.getVertice(i) * Axis;
		if (d < min) min = d;
		else if (d > max) max = d;
	}
}

//bool Collision::axisSeperatePolygon(Vector Axis, CPolygon A, CPolygon B)
//{
//	float min1,min2,max1,max2;
//
//	getInterval(A,Axis,min1,max1);
//	getInterval(B,Axis,min2,max2);
//
//	if (max2 < min1 || max1 < min2)
//		return true;
//	else return false;
//}

//bool Collision::axisSeperatePolygon(Vector Axis,CPolygon A, CPolygon B, Vector &PushVector,Vector Vel,float &Percent)
//{
//	float min1,min2,max1,max2;
//	PushVector = Axis;
//
//	getInterval(A,Axis,min1,max1);
//	getInterval(B,Axis,min2,max2);
//
//	float d1 = max1 - min2;
//	float d2 = max2 - min1;
//
//	//không xảy ra va chạm
//	if (d2 < 0 || d1 < 0)
//	{
//		//tính khoảng cách xảy ra va chạm
//		float mins = fabs(d1)<fabs(d2)?fabs(d1):fabs(d2);
//		float lengthv = Vel * Axis;
//
//		float tPercent = fabs(mins/lengthv);
//		tPercent = tPercent/100;
//		if (tPercent > Percent && tPercent < 1) 
//				Percent = tPercent;
//		return true;
//	}
//
//	else
//	{
//		float depth = d1 < d2 ? d1:d2;
//
//		float squareAxisLength = Axis * Axis;
//
//		PushVector = Axis * (float)(depth/squareAxisLength);
//		return false;
//	}
//}

int Collision::axisSeperatePolygon(Vector Axis,CPolygon A, CPolygon B, Vector &PushVector,Vector Vel, float* floatList, int &numPushVelVector)
{
	float min1,min2,max1,max2;
	PushVector = Axis;

	getInterval(A,Axis,min1,max1);
	getInterval(B,Axis,min2,max2);

	float d1 = max1 - min2;
	float d2 = max2 - min1;

	//không xảy ra va chạm
	if (d2 < 0 || d1 < 0)
	{
		d2 = fabs(d2);
		d1 = fabs(d1);
		float s = (d1 < d2) ? d1:d2;
		float v = fabs(Vel * Axis);
		if (s >= v)
			return -1;
		else
		{
			//PushVelVectorList[numPushVelVector - 1] = k * Axis;
			floatList[numPushVelVector] = (float)(1 - (float)s/v);
			numPushVelVector++;
			return 0; //willCollide
		}
	}

	else
	{
		float depth = d1 < d2 ? d1:d2;

		float squareAxisLength = Axis * Axis;

		PushVector = Axis * (float)(depth/squareAxisLength);
		return 1; //collided
	}
}

//int Collision::axisSeperatePolygon(Vector Axis,CPolygon A, CPolygon B, Vector &PushVector, Vector Vel,float &Percent)
//{
//
//	float min1,min2,max1,max2;
//	float minv,maxv;
//	PushVector = Axis;
//
//	getInterval(A,Axis,min1,max1,Vel,minv,maxv);
//	getInterval(B,Axis,min2,max2);
//
//	//not collide now
//	if (max2 < min1 || max1 < min2)
//	{
//		//but will collide in current Frame
//		if (max2 < minv || maxv < min2)
//			return true;
//		else
//		{
//			float dv1 = maxv - min2;
//			float dv2 = max2 - minv;
//
//			float depthv = dv1 < dv2 ? dv1:dv2;
//			float vInterval = Vel * Vel;
//			float tPercent = 1 - depthv/vInterval;
//
//			if (tPercent > Percent)
//				Percent = tPercent;
//			return true;
//
//		}
//	}
//
//	else
//	{
//		float d1 = max1 - min2;
//		float d2 = max2 - min1;
//
//		float depth = d1 < d2 ? d1:d2;
//
//		float squareAxisLength = Axis * Axis;
//
//		PushVector = Axis * (float)(depth/squareAxisLength);
//		return false;
//	}
//}

Vector Collision::findMTD(Vector* PushVectorList,int numItem)
{
	float minMagnitude = PushVectorList[0] * PushVectorList[0];
	int i=0;
	Vector vt;
	float curMagnitude;
	int index = 0;
	for (int i=0;i<numItem;i++)
	{
		curMagnitude = PushVectorList[i] * PushVectorList[i];
		if (curMagnitude < minMagnitude)
		{
			minMagnitude = curMagnitude;
			index = i;
		}
	}

	return PushVectorList[index];
}

Vector Collision::findPushVelVector(Vector *PushVelVectorList, int numItem)
{
	float maxMagnitude = PushVelVectorList[0] * PushVelVectorList[0];
	float curMagnitude;
	int index = 0;
	for (int i=1;i<numItem;i++)
	{
		curMagnitude = PushVelVectorList[i] * PushVelVectorList[i];
		if (curMagnitude > maxMagnitude)
		{
			maxMagnitude = curMagnitude;
			index = i;
		}
	}

	return PushVelVectorList[index];
}

float Collision::findmin(float *List, int numItem)
{
	float min = 1;
	for (int i=0;i<numItem;i++)
		if (List[i] < min)
			min = List[i];
	return min;
}

